﻿using System;
using System.IO;
using Xejen.Hosting.Extensions;
using Xejen.Logger;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Xejen.Hosting
{
    /// <summary>
    /// <inheritdoc cref="IAppHost"/>基类 
    /// </summary>
    /// <creator>marc</creator>
    public abstract class AppHostBase : IAppHost
    {
        private readonly ILogger _logger;
        private readonly ILoggerManager _loggerManager;
        /// <inheritdoc cref="ILogger"/>
        protected ILogger Logger => _logger;

        /// <summary>
        /// 服务列表
        /// </summary>
        internal IServiceCollection Services;

        /// <inheritdoc cref="HostConfiguration"/>
        public HostConfiguration HostConfig { get; private set; } = new HostConfiguration();
        /// <inheritdoc/>
        public IConfiguration Configuration { get; private set; }
        /// <inheritdoc/>
        public IServiceProvider ServiceProvider { get; private set; }
        /// <inheritdoc/>
        public ILoggerManager LoggerManager => _loggerManager;

        /// <inheritdoc/>
        public event EventHandler<IConfigurationBuilder> HostConfiguring;
        /// <inheritdoc/>
        public event EventHandler<IConfiguration> HostConfigurationInitialized;
        /// <inheritdoc/>
        public event EventHandler<IServiceCollection> HostServicesInitializing;
        /// <inheritdoc/>
        public event EventHandler HostReady;

        /// <inheritdoc cref="AppHostBase"/>
        /// <param name="args">启动参数</param>
        /// <param name="loggerManager">采用的日志方式</param>
        protected AppHostBase(string[] args, ILoggerManager loggerManager)
        {
            Check.NotNull(loggerManager, nameof(loggerManager));

            _loggerManager = loggerManager;
            _logger = _loggerManager.CreateLogger(typeof(AppHostBase));

            HostConfig = HostConfiguration.Load(args);

            PreInitialize();
            Initialize();
        }

        /// <summary>
        /// 将 ILoggerManager 添加到构造函数中
        /// </summary>
        /// <param name="loggerManager"><inheritdoc cref="ILoggerManager" path="/summary"/></param>
        protected AppHostBase(ILoggerManager loggerManager)
        {
            Check.NotNull(loggerManager, nameof(loggerManager));

            _loggerManager = loggerManager;
            _logger = _loggerManager.CreateLogger(typeof(AppHostBase));

            PreInitialize();
            Initialize();
        }

        /// <inheritdoc cref="AppHostBase"/>
        /// <param name="configuration"><inheritdoc cref="HostConfiguration" path="/summary"/></param>
        /// <param name="loggerManager"><inheritdoc cref="ILoggerManager" path="/summary"/></param>
        protected AppHostBase(HostConfiguration configuration, ILoggerManager loggerManager)
        {
            Check.NotNull(loggerManager, nameof(loggerManager));
            Check.NotNull(configuration, nameof(configuration));

            _loggerManager = loggerManager;
            _logger = _loggerManager.CreateLogger(typeof(AppHostBase));

            HostConfig = configuration;

            PreInitialize();
            Initialize();
        }

        /// <summary>
        /// 初始化前加载
        /// </summary>
        protected virtual void PreInitialize() { }

        private void Initialize()
        {
            _logger.LogInformation($"应用程始启动，开始初始化");

            InitializeConfiguration(HostConfig.ConfigDirectory);
            InitializeServices();
        }

        /// <inheritdoc/>
        public virtual IAppHost Build()
        {
            ConfigureServices(Services);

            ServiceProvider = Services.BuildServiceProvider();

            _logger.LogInformation($"服务初始化完毕，共 {Services.Count} 项服务");

            _logger.LogInformation($"程序初始化完毕");

            OnHostReady(this);

            //由于我们是自己定制主机，所以，不使用IHost。若使用IHost的话，那么本类代码都完全不需要，直接在每个应用程序的Programe中调用IHost即可创建了
            #region 使用IHost主机

            //var hostBuilder = Host.CreateDefaultBuilder()
            //    .ConfigureServices((context, services) =>
            //    {
            //        ConfigureServices(services);
            //        services.AddSingleton(_loggerManager);
            //        services.AddSingleton(Configuration);
            //        services.AddSingleton(HostConfig);
            //        services.AddSingleton<IAppHost>(this);

            //        if (Configuration.GetValue<bool>("Logging:UseEventLog"))
            //        {
            //            services.AddLogging(logging =>
            //            {
            //                logging.AddEventLog();
            //            });
            //        }
            //        else
            //        {
            //            // 添加其他日志记录器，如 File、EventSource 等，但不要添加 EventLog 日志记录器
            //            services.AddLogging(logging =>
            //            {
            //                logging.ClearProviders(); // 清除默认的日志记录器提供程序
            //                logging.AddConsole(); // 添加 Console 日志记录器
            //                logging.AddDebug(); // 添加 Debug 日志记录器
            //            });
            //        }
            //    });

            //IHost host = hostBuilder.Build();
            //ServiceProvider = host.Services;

            //_logger.LogInformation($"服务初始化完毕，共 {Services.Count} 项服务");
            //_logger.LogInformation($"程序初始化完毕");

            //OnHostReady(this);
            #endregion

            return this;
        }

        /// <inheritdoc/>
        public virtual void Run() { }

        private void InitializeConfiguration(string configDirectory)
        {
            _logger.LogInformation($"准备加载配置文件");
            if (string.IsNullOrEmpty(configDirectory))
            {
                configDirectory = AppDomain.CurrentDomain.BaseDirectory;
            }

            string appsettingFileName = HostConfig.DefaultSettingsFileName;
            if (!File.Exists(Path.Combine(configDirectory, appsettingFileName)))
            {
                throw new FileNotFoundException($"未找到 {appsettingFileName} 文件，查找目录在：\r\n{configDirectory}");
            }

            var builder = new ConfigurationBuilder()
                .SetBasePath(configDirectory)
                .AddJsonFile(appsettingFileName, optional: true, reloadOnChange: true);

            ConfigureJsonFiles(builder);

            OnHostConfiguring(this, builder);

            Configuration = builder.Build();

            OnHostConfigurationInitialized(this, Configuration);

            _logger.LogInformation($"配置文件加载完成，工作目录： {configDirectory}");
        }

        /// <summary>
        /// 配置json文件，基类已自动完成<see langword="appsettings.json"/>文件的加载，您只需加载您其它的配置文件即可
        /// </summary>
        /// <param name="configuration">传入过来的<see cref="IConfigurationBuilder"/>接口对象</param>
        protected virtual void ConfigureJsonFiles(IConfigurationBuilder configuration)
        {

        }

        /// <summary>
        /// 初始化基础服务
        /// </summary>
        private void InitializeServices()
        {
            _logger.LogInformation($"准备初始化服务");
            var services = new ServiceCollection();
            Services = services;

            // 添加服务
            // services.AddTransient<IService, ServiceImplementation>();
            // 添加主机服务：public class AppHostedService : IHostedService，该类要实现StartAsync以及StopAsync方法
            // services.AddHostedService<AppHostedService>();

            services.AddSingleton(_loggerManager);
            services.AddSingleton(Configuration);
            services.AddSingleton(HostConfig);
            services.AddSingleton<IAppHost>(this);

            OnHostServicesInitializing(this, services);
        }

        /// <summary>
        /// 配置服务，各子项目可以重写此方法来注册各项服务
        /// </summary>
        /// <param name="services">服务集合</param>
        protected virtual void ConfigureServices(IServiceCollection services)
        {

        }

        /// <inheritdoc cref="HostConfiguring" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        /// <param name="builder">用于构建应用程序配置的构建器</param>
        protected virtual void OnHostConfiguring(IAppHost sender, IConfigurationBuilder builder)
        {
            HostConfiguring?.Invoke(sender, builder);
        }

        /// <inheritdoc cref="HostConfigurationInitialized" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        /// <param name="builder">应用程序配置</param>
        protected virtual void OnHostConfigurationInitialized(IAppHost sender, IConfiguration builder)
        {
            HostConfigurationInitialized?.Invoke(sender, builder);
        }

        /// <inheritdoc cref="HostServicesInitializing" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        /// <param name="builder">服务列表</param>
        protected virtual void OnHostServicesInitializing(IAppHost sender, IServiceCollection builder)
        {
            HostServicesInitializing?.Invoke(sender, builder);
        }

        /// <inheritdoc cref="HostReady" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        protected virtual void OnHostReady(IAppHost sender)
        {
            HostReady?.Invoke(sender, EventArgs.Empty);
        }
    }
}
